package references

import (
	"JVM/Jvmgo/GoToJVM/instructions/base"
	"JVM/Jvmgo/GoToJVM/runtimeData"
	"JVM/Jvmgo/GoToJVM/runtimeData/heap"
)

/*
第一个操作数是uint16索引
第二个操作数表示数组维度
*/
type MULTI_ANEW_ARRAY struct {
	index      uint16
	dimensions uint8
}

func (self *MULTI_ANEW_ARRAY) FetchOperands(reader *base.BytecodeReader) {
	self.index = reader.ReadUint16()
	self.dimensions = reader.ReadUint8()
}

/*
执行创建多维数组
*/
func (self *MULTI_ANEW_ARRAY) Execute(frame *runtimeData.Frame) {
	cp := frame.Method().Class().ConstantPool()
	classRef := cp.GetConstant(uint(self.index)).(*heap.ClassRef)
	// 由于是二维数组，所以这里解析出来的是数组类而非是 anewarray中的数组中元素的类
	arrClass := classRef.ResolvedClass()

	stack := frame.OperandStack()
	counts := popAndCheckCounts(stack, int(self.dimensions))
	arr := newMultiDimensionalArray(counts, arrClass)
	stack.PushRef(arr)
}

func popAndCheckCounts(stack *runtimeData.OperandStack, dimensions int) []int32 {
	counts := make([]int32, dimensions)
	for i := dimensions - 1; i > 0; i-- {
		// 弹出某维数组的长度
		counts[i] = stack.PopInt()
		if counts[i] < 0 {
			panic("java.lang.NegativeArraySizeException")
		}
	}
	return counts
}

/*
创建多维数组
需要了解多维数组本质是什么。如二维数组本质上是新建一个一维数组，然后为维数组每个节点添加新数组引用指针指向数组类
可以理解为一个发散的树状结构：

|----|----|----|----| baseArray

		|
		|
	   |--|--|--| subArray
*/
func newMultiDimensionalArray(counts []int32, class *heap.Class) *heap.Object {
	count := uint(counts[0])
	// 新建底层数组
	arr := class.NewArray(count)
	// 为数组添枝
	if len(counts) > 1 {
		refs := arr.Refs()
		for i := range refs {
			// 从counts第二个参数开始
			refs[i] = newMultiDimensionalArray(counts[1:], class.ComponentClass())
		}
	}
	return arr
}
